package dnl.persistence.orm;

import org.apache.commons.lang.StringUtils;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 
 * @author Daniel Orr
 * 
 */
public abstract class SqlInsertIntoBuilder {

	private static final DateFormat debugDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.0");

	private QueryBlock insertIntoBlock;
	private QueryBlock fromBlock = new QueryBlock("from");
	private WhereBlock whereBlock = new WhereBlock();
	private QueryBlock groupByBlock = new QueryBlock("group by");
	private QueryBlock orderByBlock = new QueryBlock("order by");
	private List<Object> parameters = new ArrayList<>();

	public SqlInsertIntoBuilder() {
		super();
	}

	public SqlInsertIntoBuilder delete() {
		insertIntoBlock = new QueryBlock("delete");
		return this;
	}
	
	public SqlInsertIntoBuilder insertInto(String tableName) {
		insertIntoBlock = new QueryBlock("insert into ");
		insertIntoBlock.append(tableName);
		return this;
	}

	public SqlInsertIntoBuilder select(String select, SqlInsertIntoBuilder subselect) {
		insertIntoBlock = new QueryBlock("select");
		insertIntoBlock.append(select);
		insertIntoBlock.append(",(");
		insertIntoBlock.append(subselect.getQueryString());
		insertIntoBlock.append(")");
		addParams(subselect.getQueryParams());
		return this;
	}

	public SqlInsertIntoBuilder from(String from) {
		fromBlock.append(from);
		return this;
	}

	public SqlInsertIntoBuilder join(String join) {
		fromBlock.append(join, "join ");
		return this;
	}

	public SqlInsertIntoBuilder where(String condition, Object... values) {
		whereBlock.append(condition);
		addParams(values);
		return this;
	}

	public SqlInsertIntoBuilder whereIn(String condition, Object... values) {
		StringBuilder inClause = new StringBuilder();
		inClause.append("(");
		for (int i = 0; i < values.length - 1; i++) {
			inClause.append("?,");
		}
		inClause.append("?)");
		String s = StringUtils.replace(condition, "?", inClause.toString());
		whereBlock.append(s);
		addParams(values);
		return this;
	}

	public void openParenthesesInWhereBlock() {
		whereBlock.openParenthesesInWhereBlock();
	}

	public void closeParenthesesInWhereBlock() {
		whereBlock.closeParenthesesInWhereBlock();
	}

	public SqlInsertIntoBuilder and(String condition, Object... values) {
		whereBlock.and(condition);
		addParams(values);
		return this;
	}

	public SqlInsertIntoBuilder and() {
		whereBlock.and();
		return this;
	}

	public SqlInsertIntoBuilder or(String condition, Object... values) {
		whereBlock.or(condition);
		addParams(values);
		return this;
	}

	public SqlInsertIntoBuilder or() {
		whereBlock.or();
		return this;
	}

	public SqlInsertIntoBuilder groupBy(String groupBy) {
		groupByBlock.append(groupBy);
		return this;
	}

	public SqlInsertIntoBuilder orderBy(String orderBy) {
		return orderBy(orderBy, true);
	}

	public SqlInsertIntoBuilder orderBy(String orderBy, boolean ascending) {
		orderByBlock.append(orderBy + " " + (ascending ? "ASC" : "DESC"));
		return this;
	}

	public String getSelectBlockContent() {
		return insertIntoBlock.getContent();
	}

	public String getQueryString() {
		StringBuilder query = new StringBuilder();
		return query.append(insertIntoBlock).append(fromBlock).append(whereBlock).append(groupByBlock)
				.append(orderByBlock).toString();
	}

	public String getQueryStringDebug() {
		String queryString = getQueryString();
		for (Object param : parameters) {
			String p = String.valueOf(param);
			if (param instanceof String) {
				p = "'"+p+"'";
			}
			else if (param instanceof Date) {
				p = "'"+debugDateFormat.format((Date)param)+"'";
			}
			queryString = StringUtils.replaceOnce(queryString, "?", p);
		}
		return queryString;
	}
	
	private void addParams(Object... values) {
		for (Object object : values) {
			parameters.add(object);
		}
	}

	public Object[] getQueryParams() {
		return parameters.toArray();
	}

	@Override
	public String toString() {
		return getClass().getSimpleName() + "{\n" + getQueryStringDebug() + "\n}";
	}

}